package core;

import util.Util;

public class PdmOptimization extends Optimization implements Comparable<PdmOptimization>{
	//input variables
	private double alpha;
	private double[] urmWeights;
	private double[] relUrmWeights;
	private int[] optimizationDirections;
	//output variables
	private double profileDistance =-1d;
	

	public PdmOptimization(DmuList dmuList, int objectiveDmu, double alpha) throws CalculationException{
		super(dmuList, objectiveDmu);
		this.setAlpha(alpha);
	}
	public PdmOptimization(DmuList dmuList, int objectiveDmu, double alpha, double[] urmWeights) throws CalculationException{
		this(dmuList, objectiveDmu, alpha);
		this.setUrmWeights(urmWeights);
	}
	public PdmOptimization(DmuList dmuList, int objectiveDmu, double alpha, double[] urmWeights, int[] optimizationDirections) throws CalculationException{
		this(dmuList, objectiveDmu, alpha, urmWeights);
		this.setOptimizationDirections(optimizationDirections);
	}
	public PdmOptimization(DmuList dmuList, int objectiveDmu, double alpha, double[] urmWeights, Optimization deaOptimization) throws CalculationException{
		this(dmuList, objectiveDmu, alpha, urmWeights);
		this.setOptimizationDirections(deaOptimization);
	}
	public void setUrmWeights(double[] urmWeights) throws CalculationException{
		if(!super.isCalculated){
			if(urmWeights.length != super.dmuList.outputSize){
				Util.print("Number of UrmWeights does not macht number of output criteria");
				System.exit(0);
			}
			this.urmWeights = urmWeights;
			setRelativeCriteriaUrmWeights();
		}
		else{
			throw new CalculationException(CalculationException.alreadyCalculatedMessage);
		}
	}
	private void setRelativeCriteriaUrmWeights(){
		relUrmWeights = new double[urmWeights.length];
		for(int w = 0; w < urmWeights.length;w++){
			relUrmWeights[w] = Util.truncate(urmWeights[w]/urmWeights[0], 5);
		}
	}
	public double[] getRelUrmWeights() {
		return relUrmWeights;
	}
	public double getRelUrmWeight(int index) {
		return relUrmWeights[index];
	}
	public int[] getOptimizationDirections(){
		return this.optimizationDirections;
	}
	public int getOptimizationDirection(int i) throws CalculationException {
		if(optimizationDirections[i] == 0){
			throw new CalculationException(CalculationException.directionNotSetMessage);
		}
		return optimizationDirections[i];
	}
	public void setOptimizationDirections(int[] optimizationDirections) throws CalculationException {
		if(!super.isCalculated){
			this.optimizationDirections = optimizationDirections;
		}else{
			throw new CalculationException(CalculationException.alreadyCalculatedMessage);
		}
	}
	public void setOptimizationDirections(Optimization deaOptimization) throws CalculationException{
		this.setOptimizationDirections(PdmOptimization.getOptimizationDirections(deaOptimization, relUrmWeights));
	}
	private static int[] getOptimizationDirections(Optimization deaOptimization, double[] relUrmWeights) throws CalculationException{
		int[] directions = new int[relUrmWeights.length];
		for(int x = 0;x < relUrmWeights.length;x++){
			if (deaOptimization.getOptimizationWeight(x) / deaOptimization.getOptimizationWeight(0) >
				relUrmWeights[x]) {
				directions[x] = 1;
			} else {
				directions[x] = -1;
			}
		}
		return directions;
	}
	public void setAlpha(double alpha) throws CalculationException {
		if(!super.isCalculated){
			this.alpha = alpha;
		}else{
			throw new CalculationException(CalculationException.alreadyCalculatedMessage);
		}
	}
	public double getAlpha() {
		return alpha;
	}
	public void setProfileDistance(double profileDistance) {
		this.profileDistance = profileDistance;
	}
	public double getProfileDistance() throws CalculationException {
		if(super.isCalculated){
			if(this.profileDistance > -1){
				return profileDistance;
			}
			else{
				this.calculateProfileDistance();
				return profileDistance;
			}
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
	}
	private void calculateProfileDistance() throws CalculationException{
		double dist = 0.0;
		double tmp = 0.0; 
		 for (int z = 0; z < dmuList.outputSize; z++) {
			 tmp = getOptimizationDirection(z) * 
			 (getOptimizationWeight(z) - 
					 getRelUrmWeight(z) * 
					 getOptimizationWeight(0)
					 );
			 dist += Math.abs(tmp);
			 //Util.print(getOptimizationDirection(z) + " - "+getOptimizationWeight(z) + " - " + getRelUrmWeight(z)+ " - "+getOptimizationWeight(0));
		 }
		 this.setProfileDistance(dist);
	}
	@Override
	public int compareTo(PdmOptimization o) {
		if(this.profileDistance > o.profileDistance){
			return -1;
		}
		else{
			return 1;
		}
	}
}
